package cn.webank.framework.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

import bsp.encrypt.EncryptUtil;
import bsp.encrypt.ParamType;
import cn.webank.framework.exception.SysException;

public class WeBankEncryptUtil {
	private final static String RSA_PREFIX = "{RSA}";
	private final static String COMMENT_PREFIX = "-----";
	private static String sysPubKeyStr = null;
	private static String appPrivKeyStr = null;

	private static String sysPrivKeyStr = null;
	private static String appPubKeyStr = null;

	private static String copyFileToString(FileReader r) throws IOException {
		BufferedReader reader = null;
		StringBuffer sb = new StringBuffer();
		try {
			reader = new BufferedReader(r);
			String tmp = null;
			while ((tmp = reader.readLine()) != null) {
				if (!tmp.startsWith(COMMENT_PREFIX)) {
					sb.append(tmp);
				}
			}

		} catch (IOException e) {
			throw e;
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException ex) {
					throw new SysException("io exception", ex);
				}
			}
		}
		return sb.toString();
	}

	/**
	 * 初始化解密密钥文件，并cache
	 * 
	 * @param sysPubKeyFilePath
	 *            系统公钥文件目录
	 * @param appPrivKeyFilePath
	 *            应用私钥文件目录
	 * @throws IOException
	 *             IO异常
	 */
	private static void initDecryptKeyStrs(String sysPubKeyFilePath, String appPrivKeyFilePath) throws IOException {
		if (sysPubKeyStr == null && StringUtils.hasText(sysPubKeyFilePath)) {
			File sf = ResourceUtils.getFile(sysPubKeyFilePath);
			Assert.notNull(sf, "sys public key file path is error");
			sysPubKeyStr = copyFileToString(new FileReader(sf));
		}

		if (appPrivKeyStr == null && StringUtils.hasText(appPrivKeyFilePath)) {
			File af = ResourceUtils.getFile(appPrivKeyFilePath);
			Assert.notNull(af, "app private key file path is error");
			appPrivKeyStr = copyFileToString(new FileReader(af));
		}
	}

	/**
	 * 初始化加密密钥文件，并cache
	 * 
	 * @param sysPrivKeyFilePath
	 *            系统私钥文件目录
	 * @param appPrivKeyFilePath
	 *            应用公钥文件目录
	 * @throws IOException
	 *             IO异常
	 */
	private static void initEncryptKeyStrs(String sysPrivKeyFilePath, String appPubKeyFilePath) throws IOException {

		if (sysPrivKeyStr == null && StringUtils.hasText(sysPrivKeyFilePath)) {
			File sf = ResourceUtils.getFile(sysPrivKeyFilePath);
			Assert.notNull(sf, "sys private key file path is error");
			sysPrivKeyStr = copyFileToString(new FileReader(sf));
		}

		if (appPubKeyStr == null && StringUtils.hasText(appPubKeyFilePath)) {
			File af = ResourceUtils.getFile(appPubKeyFilePath);
			Assert.notNull(af, "app public key file path is error");
			appPubKeyStr = copyFileToString(new FileReader(af));
		}

	}

	/**
	 * 基于发布平台公钥和应用私钥的rsa算法加密
	 *
	 * @param sysPrivKeyFilePath
	 *            发布平台私钥文件路径
	 * @param appPubKeyFilePath
	 *            应用公钥文件路径
	 * @param text
	 *            明文
	 * @return 密文
	 * @throws IOException
	 *             IO异常
	 */
	public static String rsaEncrypt(String sysPrivKeyFilePath, String appPubKeyFilePath, String text)
			throws IOException {
		Assert.notNull(sysPrivKeyFilePath, "sys private key file path is null");
		Assert.notNull(appPubKeyFilePath, "app pubic key file path is null ");
		Assert.notNull(text, "text is null");

		initEncryptKeyStrs(sysPrivKeyFilePath, appPubKeyFilePath);

		Assert.notNull(sysPrivKeyStr, "sys private key file is null");
		Assert.notNull(appPubKeyStr, "app public key file is null");

		try {
			return RSA_PREFIX
					+ EncryptUtil.encrypt(ParamType.STRING, appPubKeyStr, ParamType.STRING, sysPrivKeyStr, text);
		} catch (Exception e) {
			throw new SysException("encrypt error", e);
		}

	}

	/**
	 * 基于发布平台公钥和应用私钥的rsa算法解密
	 * 
	 * @param sysPubKeyFilePath
	 *            发布平台公钥文件路径
	 * @param appPrivKeyFilePath
	 *            应用私钥文件路径
	 * @param encrtyptText
	 *            密文
	 * @return 明文
	 * @throws IOException
	 *             IO异常
	 */
	public static String rsaDecrypt(String sysPubKeyFilePath, String appPrivKeyFilePath, String encrtyptText)
			throws IOException {

		Assert.notNull(sysPubKeyFilePath, "sys pubic key file path is null");
		Assert.notNull(appPrivKeyFilePath, "app private key file path is null ");
		Assert.notNull(encrtyptText, "encrtyptText is null");

		initDecryptKeyStrs(sysPubKeyFilePath, appPrivKeyFilePath);

		Assert.notNull(sysPubKeyStr, "sys public key file is null");
		Assert.notNull(appPrivKeyStr, "app private key file is null");

		if (StringUtils.hasText(encrtyptText) && encrtyptText.length() > RSA_PREFIX.length()
				&& encrtyptText.startsWith(RSA_PREFIX)) {

			String text = encrtyptText.startsWith(RSA_PREFIX) ? encrtyptText.substring(RSA_PREFIX.length())
					: encrtyptText;
			try {

				return EncryptUtil.decrypt(ParamType.STRING, sysPubKeyStr, ParamType.STRING, appPrivKeyStr,
						ParamType.STRING, text);
			} catch (Exception e) {
				throw new SysException("decrypt error", e);
			}
		}

		return encrtyptText;
	}
}
